#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include<unistd.h>
#include <signal.h>

#include "modbus_dev_driver.h"
#include "CRC.h"
#include "common.h"
#include "usb_hotplug_check.h"
#include "env_ctrol_service.h"

STRUCT_MODBUS_DEVICE_INFO ModbusDevStru = {0x00};

/***********************************************************
*
*函数名:modbus_device_find_index
*
*作用：根据DEVID 查找设备在存储区中的索引位置
*参数: 无
*
*返回值 ：0
************************************************************/
int modbus_device_find_index(uint8_t devid)
{
	return 0;
}

/***********************************************************
*
*函数名:modbus_device_init
*
*作用：modbus device init
*
*参数: channel :数据传输通道
*       bautrate :串口传输波特率
*返回值 ：0
************************************************************/
uint8_t modbus_device_init(uint8_t channel,uint32_t buatrate,uint8_t initstate)
{

    memset (&ModbusDevStru,0,sizeof(STRUCT_MODBUS_DEVICE_INFO));

	ModbusDevStru.channelid = channel;
	ModbusDevStru.serialbuadrate = buatrate;
	ModbusDevStru.serialinitok = initstate;

	return 0;
}

/***********************************************************
*
*函数名:modbus_device_add
*
*作用:在总线上增加设备
*
*参数: 无
*
*返回值 ：-1:设备添加失败 	!(-1) :设备添加成功
************************************************************/
int modbus_device_add(uint8_t devid)
{
	return 0;
}

/***********************************************************
*
*函数名:modbus_device_del
*
*作用：删除总线上的设备
*
*参数: 无
*
*返回值 ：-1:设备添加失败 	!(-1) :设备添加成功
************************************************************/
int modbus_device_del(uint8_t devid)
{
	return 0;
}


/***********************************************************
*
*函数名:modbus_device_pack_data
*
*作用：将要发送的数据打包成modbus标准格式
*
*参数: devid :设备地址
	     wrtype :数据操作方式 ：读、写
	     datatype :数据类型 ,0:离散量输出 1：离散量输入 2：寄存器保持  3：寄存器输入
	   startaddr：数据起始地址
	   num :数据个数
	   sendbuf :发送缓冲区指针	
*
*返回值 ：打包数据长度
************************************************************/
uint8_t modbus_device_pack_data(uint8_t devid,uint8_t wrtype,uint8_t *datatype, uint32_t startaddr, uint16_t num,uint8_t *sendbuf)
{

	uint16_t i = 0x00;
	
	uint8_t  cnt = 0x00;
	uint8_t len = 0x00;

	uint8_t  nbyte = 0x00;	

	uint32_t tmp = 0x00;
	uint16_t tmpcrc = 0x00;

	uint8_t func = 0x00;
	
	uint32_t offset1 = 0x00;
	uint32_t offset2 = 0x00;

	/*根据读写方式及要读写的数据类型确定读写功能码 */
	if (wrtype == 0x00)
	{
		/*读取离散量*/
		if ((*datatype == 0x00))
		{
			func = READ_COIL_STATUS;
		}
		else if ((*datatype == 0x01))
		{
			func = READ_INPUT_STATUS;
		}
		else if ((*datatype == 0x02))
		{
			func = READ_HOLD_REGISTERS;
		}
		else if ((*datatype == 0x03))
		{
			func = READ_INPUT_REGISTERS;
		}
	}
	else if (wrtype == 0x01)
	{

		/*设置离散量*/
		if ((*datatype == 0x00))
		{
			if (num >1)
			{
				func = FORCE_MULTIPLE_COILS;
			}
			else
			{
				func = FORCE_SINGLE_COIL;
			}
		}
		else if ((*datatype == 0x02))
		{
			if (num >1)
			{
				func = PRESET_MULTIPLE_REGS;
			}
			else
			{
				func = PRESET_SINGLE_REGISTER;
			}
		}
		
	}
	
	/*功能码*/
	switch (func)
	{

		/*读取离散量值*/
		case READ_COIL_STATUS:
		case READ_INPUT_STATUS:
		{
			
			sendbuf[cnt] = devid;
			cnt ++;
			sendbuf[cnt] = func;
			cnt ++;

			sendbuf[cnt] = (startaddr >> 8) & 0x000000ff;
			cnt ++;
			sendbuf[cnt] = startaddr & 0x000000ff;
			cnt ++;	

			sendbuf[cnt] = (num >> 8) & 0x000000ff;
			cnt ++;
			sendbuf[cnt] = num & 0x000000ff;
			cnt ++; 

		}
		break;

		/*强制离散量值*/
		case FORCE_SINGLE_COIL:
		case FORCE_MULTIPLE_COILS:
		{
			
			sendbuf[cnt] = devid;
			cnt ++;
			sendbuf[cnt] = func;
			cnt ++;

			sendbuf[cnt] = (startaddr >> 8) & 0x000000ff;
			cnt ++;
			sendbuf[cnt] = startaddr & 0x000000ff;
			cnt ++;	

			nbyte = (num / 8) + ((num % 8) ? 1 : 0);
			
			/*设置多个离散量*/
			if (num > 0x01)
			{
				
				sendbuf[cnt] = (num >> 8)& 0x000000ff;
				cnt ++;
				
				sendbuf[cnt] = num & 0x000000ff;
				cnt ++; 

				sendbuf[cnt] = nbyte;
				cnt ++; 	
			}

			offset1 = startaddr % 32;
			for (i = 0;i < num ;i ++)
			{
				
				tmp = ModbusDevStru.inputandcoilstatus.all[(startaddr + i) / 32] >> (offset1 ++);
				tmp &= 0x00000001;

				if (num == 0x01)
				{

					/*01 :对应[ff][00]   00:对应[00][00]*/
					if (tmp == 0x00000001)
					{
						sendbuf[cnt]  = 0xff;
					}
					else
					{
						sendbuf[cnt]  = 0x00;
					}
					cnt ++;
					
					sendbuf[cnt]  = 0x00;
					cnt ++;
					
					break;
				}

				if (offset1 == 0x20)
				{
					offset1 = 0x00;
				}

				sendbuf[cnt]  |= (tmp << (offset2 ++));
				//offset2 ++;
				
				if (((offset2 % 8) == 0) && (offset2 > 0))
				{
					cnt ++;
					offset2 = 0x00;
				}
				
				else if (i == (num - 1))
				{
					cnt ++ ;
				}
			}
				
		}
		break;

		/*读取寄存器值*/
		case READ_HOLD_REGISTERS:
		case READ_INPUT_REGISTERS:
		{
			sendbuf[cnt] = devid;
			cnt ++;
			sendbuf[cnt] = func;
			cnt ++;

			
			sendbuf[cnt] = (startaddr >> 8) & 0x000000ff;
			cnt ++;
			sendbuf[cnt] = startaddr & 0x000000ff;
			cnt ++;	

			sendbuf[cnt] = (num >> 8) & 0x000000ff;
			cnt ++;
			sendbuf[cnt] = num & 0x000000ff;
			cnt ++; 			
			
		}
		break;

		/*设置寄存器值*/
		case PRESET_SINGLE_REGISTER:
		case PRESET_MULTIPLE_REGS:
		{
			
		    sendbuf[cnt] = devid;
			cnt ++;
			sendbuf[cnt] = func;
			cnt ++;

			sendbuf[cnt] = (startaddr >> 8) & 0x000000ff;
			cnt ++;
			sendbuf[cnt] = startaddr & 0x000000ff;
			cnt ++;	
			
			if (num > 0x01)
			{
				
				sendbuf[cnt] = (num >> 8)& 0x000000ff;
				cnt ++;
				
				sendbuf[cnt] = num & 0x000000ff;
				cnt ++; 

				sendbuf[cnt] = (2 * num);
				cnt ++; 	
			}
			
			for (i = 0;i < num ;i ++)
			{

				sendbuf[cnt] = ModbusDevStru.holdandindatareg[ startaddr + i] >> 8;
				cnt ++;
				
				sendbuf[cnt] = ModbusDevStru.holdandindatareg[startaddr + i ];
				cnt ++;
			}
				
		}
		break;

		/**/
		default:
        {
            return 0;
        }
			break;
		
	}

	len = cnt;
	
	tmpcrc = usMBCRC16(sendbuf,len);
	len += 2;	

	/*crc value*/
	sendbuf[len - 2] = tmpcrc ;	
	sendbuf[len - 1] = tmpcrc >> 8;

	//ModbusDevStru.moddevstate = MODBUS_DEVICE_OFFLINE;
	*datatype = func;
	return (len);
}

/***********************************************************
*
*函数名:modbus_device_pack_data
*
*作用：将要发送的数据打包成modbus标准格式
*
*参数: 
	   pdata：接收数据缓冲
	   len:接收到的数据长度
	   
	   devid :设备地址
	   func:功能码
	   startaddr：数据起始地址
	   num :数据个数
*
*返回值 ：！0：数据接收成功 0:数据接收失败
************************************************************/
uint8_t modbus_device_unpack_data(uint8_t *pdata,uint8_t len,uint8_t devid,uint8_t func, uint32_t startaddr, uint16_t num)
{

	uint8_t  i 		= 0x00;
	uint8_t  cnt 	= 0x00;

	uint8_t  nbyte 	= 0x00;

	uint16_t tmpcrc = 0x00;
	uint16_t calcrc = 0x00;

	int tmp = 0x00;

//	for (i = 0x00;i < len;i ++)
//	{
//		LOGD (" %02x ",pdata[i]);
//	}
//	LOGD ("\n");
	
	/*接收帧长度大于最小帧长度*/
	if (len <= RECV_FRAME_MINI_LENGTH)
	{
		return 0;
	}

	/*crc校验*/
	tmpcrc = pdata[len - 2 ] | (pdata[len - 1 ] << 8);
	calcrc = usMBCRC16(pdata,len - 2);

	if (calcrc != tmpcrc)
	{
		return 0;
	}

	/*发送帧的设备地址 :作为一帧数据发送之后的等待接收帧标记记录*/
	if ((devid != pdata[cnt ++]))
	{
		return 0;
	}

	/*功能码字段*/
	if ((func != pdata[cnt ++]))
	{
		return 0;
	}

	switch(func)
	{
		case READ_COIL_STATUS:
		case READ_INPUT_STATUS:
		{

			nbyte = pdata[cnt];
			cnt ++;

			/*判断当前接受的帧长度是否与期待接收到的帧长度一致*/
			for (i = 0x00;i < num;i ++)
			{

				/*离散量值*/
				tmp = pdata[cnt + (i / 8)] >> (i % 8);
				tmp &= 0x00000001;

				ModbusDevStru.inputandcoilstatus.all[(startaddr + i) / 32] &= ~(0x1 << ((startaddr + i) % 32));
				ModbusDevStru.inputandcoilstatus.all[(startaddr + i) / 32] |= tmp << ((startaddr + i) % 32);
			}
		}
		break;

		case FORCE_SINGLE_COIL:
		case FORCE_MULTIPLE_COILS:
		{

		}

		break;

		case READ_HOLD_REGISTERS:
		case READ_INPUT_REGISTERS:
		{

			nbyte = pdata[cnt];
			cnt ++;

			/**/
			for (i = 0;i < (num);i ++)
			{
				ModbusDevStru.holdandindatareg[startaddr + i] = (pdata[cnt] << 8);
				cnt ++;
				
				ModbusDevStru.holdandindatareg[startaddr + i] |= pdata[cnt];
				cnt ++;
			}

		}
		break;

		case PRESET_SINGLE_REGISTER:
		case PRESET_MULTIPLE_REGS:
		{
				
		}
		break;

		case READ_COIL_STATUS | 0x80:
		case READ_INPUT_STATUS | 0x80:
		case FORCE_SINGLE_COIL | 0x80:
		case FORCE_MULTIPLE_COILS | 0x80:
		case READ_HOLD_REGISTERS | 0x80:
		case READ_INPUT_REGISTERS | 0x80:
		case PRESET_SINGLE_REGISTER | 0x80:
		case PRESET_MULTIPLE_REGS | 0x80:
		{
			//printf ("slave device deal error");
		}
		break;

		default:
			break;
	}

	//ModbusDevStru.moddevstate = MODBUS_DEVICE_ONLINE;
	return (cnt);
}


/***********************************************************
*
*函数名:
*
*作用：获取modbus 设备控制通道
*
*	
*
*返回值 :0x00 ：有可用的传输通道  0x01 ：无可用传输通道
************************************************************/
uint8_t modbus_device_get_cmd_channel(uint8_t * channel)
{

	uint8_t ret = 0x00;
	if (ModbusDevStru.serialinitok != USB_SERIAL_DEVICE_INIT_OK)
	{
		ret = 0x01;
	}
	else
	{
		if (ModbusDevStru.channelid > USB_SERIAL_AMOUNT)
		{
			ret = 0x01;
		}
		else
		{
			*channel = ModbusDevStru.channelid ;
		}
	}

	return ret;
}



////////////////////////////////////////////////////////////////////////////////////////
